package com.gitee.easyopen.support;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.interfaces.RSAPrivateKey;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.OAuthResponse;
import org.apache.velocity.VelocityContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.fastjson.JSON;
import com.gitee.easyopen.ApiConfig;
import com.gitee.easyopen.ApiContext;
import com.gitee.easyopen.ApiResult;
import com.gitee.easyopen.ApiValidator;
import com.gitee.easyopen.Encrypter;
import com.gitee.easyopen.Invoker;
import com.gitee.easyopen.ParamNames;
import com.gitee.easyopen.RespWriter;
import com.gitee.easyopen.Result;
import com.gitee.easyopen.auth.Oauth2Manager;
import com.gitee.easyopen.auth.Oauth2Service;
import com.gitee.easyopen.bean.ApiSearch;
import com.gitee.easyopen.bean.Consts;
import com.gitee.easyopen.bean.RequestMode;
import com.gitee.easyopen.doc.ApiDocBuilder;
import com.gitee.easyopen.doc.ApiDocHolder;
import com.gitee.easyopen.exception.ApiException;
import com.gitee.easyopen.interceptor.ApiInterceptor;
import com.gitee.easyopen.limit.LimitConfig;
import com.gitee.easyopen.limit.LimitConfigManager;
import com.gitee.easyopen.limit.LimitSearch;
import com.gitee.easyopen.message.Errors;
import com.gitee.easyopen.monitor.MonitorApiInfo;
import com.gitee.easyopen.monitor.MonitorStore;
import com.gitee.easyopen.register.AbstractInitializer;
import com.gitee.easyopen.util.MD5Util;
import com.gitee.easyopen.util.RequestUtil;
import com.gitee.easyopen.util.VelocityUtil;

/**
 * 提供API访问能力,新建一个类继承这个即可.RequestMapping中的value自己定义
 * 
 * <pre>
 * &#64;Controller
 * &#64;RequestMapping(value = "/api")
 * public class IndexController extends ApiController {
 * }
 * 
 * 这样接口的统一访问路径为:http://ip:port/contextPath/api
 * </pre>
 */
public abstract class ApiController extends AbstractInitializer implements ApplicationListener<ContextRefreshedEvent> {
    
    private static final String SESSION_KEY_MONITOR_PASSWORD = "session_key_monitor_password";
    private static final String SESSION_KEY_DOC_PASSWORD = "session_key_doc_password";
    
    protected InvokeTemplate invokeTemplate = new InvokeTemplate();
    protected WebfluxInvokeTemplate webfluxInvokeTemplate = new WebfluxInvokeTemplate();
    
    protected ApiConfig apiConfig;
    
    @Autowired(required = false)
    protected Oauth2Manager oauth2Manager;
    
    protected Oauth2Service oauth2Service;
    
    protected Invoker invoker;

    // spring容器加载完毕后执行
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        ApplicationContext applicationContext = getRootApplicationContext(event.getApplicationContext());
        ApiContext.setApplicationContext(applicationContext);
        
        this.apiConfig = newApiConfig();
        ApiContext.setApiConfig(apiConfig);
        
        apiConfig.loadPrivateKey();
        
        this.initApiConfig(this.apiConfig);

        this.init(applicationContext, this.apiConfig);
        
        this.initComponent(); // 放在最后
    }
    
    protected ApplicationContext getRootApplicationContext(ApplicationContext applicationContext) {
        ApplicationContext rootApplicationContext = applicationContext.getParent();
        return rootApplicationContext != null ? rootApplicationContext : applicationContext;
    }
    
    protected ApiConfig newApiConfig() {
        return new ApiConfig();
    }
    
    private void initComponent() {
        if(oauth2Manager != null) {
            apiConfig.initOauth2Service(oauth2Manager);
            oauth2Service = apiConfig.getOauth2Service();
        }
        invoker = apiConfig.getInvoker();
        
        initInterceptor();
    }
    
    // 添加监控拦截器
    private void initInterceptor() {
        if(this.apiConfig.isShowMonitor()) {
            ApiInterceptor[] interceptors = this.apiConfig.getInterceptors();
            int len = interceptors.length + 1;
            ApiInterceptor[] newInterceptors = new ApiInterceptor[len];
            newInterceptors[0] = this.apiConfig.getMonitorInerceptor(); // 监控拦截器放在首位
            for (int i = 0; i < interceptors.length; i++) {
                newInterceptors[i + 1] = interceptors[i];
            }
            this.apiConfig.setInterceptors(newInterceptors);
        }
    }
    
    /**
     * 请求入口
     * 
     * @param request
     * @param response
     * @throws Throwable
     */
    @RequestMapping(method = {RequestMethod.POST, RequestMethod.GET})
    public void index(HttpServletRequest request, HttpServletResponse response) throws Throwable {
        this.invokeTemplate.processInvoke(request, response);
    }
    
    /**
     * 加密请求入口
     * @param request
     * @param response
     * @throws Throwable
     */
    @RequestMapping(value = "ssl", method = RequestMethod.POST)
    public void ssl(HttpServletRequest request, HttpServletResponse response) throws Throwable {
        this.invokeTemplate.processInvokeBySSL(request, response);
    }
    
    /* ********************** */
    // 这里将返回结果暴露在Controller层,之前是在ApiInvoker里面.
    // 这样做灵活一点,以后还可以做WebFlux
    /* ********************** */
    /**
     * 调用业务方法
     * @param request
     * @param response
     * @return 返回结果对象
     * @throws Throwable 
     */
    private Object invoke(HttpServletRequest request, HttpServletResponse response) throws Throwable {
        // 调用接口方法,即调用被@Api标记的方法
        ApiContext.setRequestMode(RequestMode.SIGNATURE);
        return this.invoker.invoke(request, response);
    }
    
    
    /**
     * 调用业务方法,加密模式
     * @param request
     * @param response
     * @return 返回结果对象
     * @throws Throwable 
     */
    private Object invokeBySSL(HttpServletRequest request, HttpServletResponse response) throws Throwable {
        ApiContext.setRequestMode(RequestMode.ENCRYPT);
        return this.invoker.invoke(request, response);
    }
    
    
    /**
     * 写数据到客户端
     * @param response
     * @param result 结果
     * @param format 返回类型，json,xml之一
     */
    public void responseResult(HttpServletResponse response, Object result) {
        if(result == null) {
            return;
        }
        RespWriter respWriter = this.apiConfig.getRespWriter();
        respWriter.write(response, result);
    }

    /**
     * 文档页面
     * 
     * @param request
     * @param response
     * @throws Throwable
     */
    @RequestMapping("doc")
    public void doc(HttpServletRequest request, HttpServletResponse response) throws Throwable {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=UTF-8");
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        
        if (!this.apiConfig.isShowDoc()) {
            response.getWriter().write("文档功能未开启");
            return;
        }        
        
        Object value = request.getSession().getAttribute(SESSION_KEY_DOC_PASSWORD);
        VelocityContext context = this.buildVelocityContext(request);
        String requestUrl = request.getRequestURL().toString();
        context.put("apiUrl", requestUrl.subSequence(0, requestUrl.length() - 4));
        // 如果设置了密码，且没有登陆
        if(StringUtils.hasText(this.apiConfig.getDocPassword()) && value == null) {
            // 校验登陆密码
            if(this.checkDocPassword(request)) { // 错误密码
                request.getSession().setAttribute(SESSION_KEY_DOC_PASSWORD, true);
                response.sendRedirect(String.valueOf(context.get("loginUrl")));
                return;
            } else {
                               
                ClassPathResource res = new ClassPathResource(this.apiConfig.getLoginClassPath());
                context.put("title", "API文档");
                context.put("remark", "文档页面密码：");
                
                VelocityUtil.generate(context, res.getInputStream(), response.getWriter());
                return;
            }
        } else { // 没有设置密码或已经登录
            ClassPathResource res = new ClassPathResource(this.apiConfig.getDocClassPath());

            context.put("title", "API文档");
            ApiDocBuilder docBuilder = ApiDocHolder.getApiDocBuilder();
            context.put("apiModules", docBuilder.getApiModules());
            
            context.put("ACCESS_TOKEN_NAME", ParamNames.ACCESS_TOKEN_NAME);
            context.put("API_NAME", ParamNames.API_NAME);
            context.put("APP_KEY_NAME", ParamNames.APP_KEY_NAME);
            context.put("DATA_NAME", ParamNames.DATA_NAME);
            context.put("FORMAT_NAME", ParamNames.FORMAT_NAME);
            context.put("SIGN_METHOD_NAME", ParamNames.SIGN_METHOD_NAME);
            context.put("SIGN_NAME", ParamNames.SIGN_NAME);
            context.put("TIMESTAMP_NAME", ParamNames.TIMESTAMP_NAME);
            context.put("TIMESTAMP_PATTERN", ParamNames.TIMESTAMP_PATTERN);
            context.put("VERSION_NAME", ParamNames.VERSION_NAME);
            
            context.put("code_name", "code");
            context.put("code_description", "状态值，\"0\"表示成功，其它都是失败");
            
            context.put("msg_name", "msg");
            context.put("msg_description", "错误信息，出错时显示");
            
            context.put("data_name", "data");
            context.put("data_description", "返回的数据，没有则返回{}");
            
            context.put("docRemark", this.getDocRemark());
            
            context.put("jsHook", "");
            
            this.processDocVelocityContext(context);

            VelocityUtil.generate(context, res.getInputStream(), response.getWriter());
        }
    }
    
    /**
     * 文档页顶部说明，支持html标签
     * @return
     */
    protected String getDocRemark() {
        return "";
    }
    
    protected VelocityContext buildVelocityContext(HttpServletRequest request) {
        VelocityContext context = new VelocityContext();
        String requestUrl = request.getRequestURL().toString();
        context.put("url", requestUrl);
        context.put("ctx", request.getContextPath());
        context.put("loginUrl", getLoginUrl(requestUrl));
        return context;
    }
    
    protected String getLoginUrl(String requestUrl) {
        return requestUrl.substring(requestUrl.lastIndexOf("/") + 1);
    }
    
    
    protected boolean checkDocPassword(HttpServletRequest request) {
        return this.checkPassword(request, this.apiConfig.getDocPassword());
    }
    
    protected boolean checkPassword(HttpServletRequest request,String serverPwd) {
        String inputPassword = request.getParameter("p");
        if(inputPassword == null) {
            return false;
        }
        if(serverPwd == null) {
            return false;
        }
        return MD5Util.encrypt(serverPwd).equals(inputPassword);
    }
    
    /**
     * 对doc模板做额外处理
     * @param context
     */
    protected void processDocVelocityContext(VelocityContext context) {
        
    }
    
    /**
     * 进入监控页面
     * @param monitorSearch 查询参数
     * @return
     * @throws IOException 
     * @throws ServletException 
     */
    @RequestMapping("monitor")
    public void monitor(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        if (!this.apiConfig.isShowMonitor()) {
            response.getWriter().write("监控功能未开启");
            return;
        }
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=UTF-8");
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        
        Object value = request.getSession().getAttribute(SESSION_KEY_MONITOR_PASSWORD);
        VelocityContext context = this.buildVelocityContext(request);
        // 如果没有登陆
        if(value == null) {
            // 校验登陆密码
            if(this.checkMonitorPassword(request)) {
                request.getSession().setAttribute(SESSION_KEY_MONITOR_PASSWORD, true);
                response.sendRedirect(String.valueOf(context.get("loginUrl")));
                return;
            } else { // 密码错误跳转
                request.getSession().setAttribute(SESSION_KEY_MONITOR_PASSWORD, null);
                
                ClassPathResource res = new ClassPathResource(this.apiConfig.getLoginClassPath());
                
                context.put("title", "API监控");
                context.put("remark", "监控页面密码：");
                
                VelocityUtil.generate(context, res.getInputStream(), response.getWriter());
                return;
            }
        } else { // 已登录
            ClassPathResource res = new ClassPathResource(this.apiConfig.getMonitorClassPath());

            context.put("title", "监控");
            context.put("errorSize", this.apiConfig.getMonitorErrorQueueSize());
            
            this.processMonitorVelocityContext(context);
            
            VelocityUtil.generate(context, res.getInputStream(), response.getWriter());
        }
    }
    
    protected boolean checkMonitorPassword(HttpServletRequest request) {
        return this.checkPassword(request, this.apiConfig.getMonitorPassword());
    }
    
    /**
     * 对监控模板做额外处理
     * @param context
     */
    protected void processMonitorVelocityContext(VelocityContext context) {
        
    }
    
    // 查询监控数据
    @RequestMapping("monitor/data")
    @ResponseBody
    public Object monitorData(ApiSearch apiSearch,HttpServletRequest request) throws IOException {
        if(request.getSession().getAttribute(SESSION_KEY_MONITOR_PASSWORD) == null) { // 无权限
            return -1;
        }
        MonitorStore store = this.apiConfig.getMonitorStore();
        long total = store.getTotal(apiSearch);
        List<MonitorApiInfo> list = store.getList(apiSearch);
        
        Map<String, Object> map = new HashMap<>();
        map.put("total", total);
        map.put("rows", list);
        
        return map;
    }
    
    // 删除监控数据
    @RequestMapping("monitor/del")
    @ResponseBody
    public Object monitorDel(String name,String version) throws IOException {
        MonitorStore store = this.apiConfig.getMonitorStore();
        store.clean(name, version);
        return Collections.emptyMap();
    }
    
    /**
     * 交换随机码
     * @param request
     * @param response
     * @return
     * @throws Throwable
     */
    @RequestMapping(value = "handshake", method = RequestMethod.POST)
    @ResponseBody
    public Object handshake(HttpServletRequest request, HttpServletResponse response) throws Throwable {
        try {
            String randomKeyEncrypted = RequestUtil.getText(request);
            Encrypter encrypter = this.apiConfig.getEncrypter();
            String privateKey = this.apiConfig.getPrivateKey();
            if(StringUtils.isEmpty(privateKey)) {
                logger.error("未设置正确的私钥");
                throw Errors.ERROR_SSL.getException();
            }
            RSAPrivateKey priKey = encrypter.getPrivateKey(privateKey);
            // 得到客户端传来的随机码
            String randomKey = encrypter.rsaDecryptByPrivateKey(randomKeyEncrypted, priKey);
            request.getSession().setAttribute(Consts.RANDOM_KEY_NAME, randomKey);
            // 再用随机码进行加密,返回给客户端
            // 客户端如果能解开,说明两边对接成功
            // 后续的数据传输都通过这个随机码进行加解密操作
            String retContent = "0";
            String aesStr = encrypter.aesEncryptToHex(retContent, randomKey);
            
            String data = encrypter.rsaEncryptByPrivateKey(aesStr, priKey);
            
            ApiResult result = new ApiResult();
            result.setCode(Errors.SUCCESS.getCode());
            result.setData(data);
            
            return result;
        }catch (Exception e) {
            logger.error(e.getMessage(), e);
            ApiResult result = new ApiResult();
            result.setCode(Errors.ERROR_SSL.getCode());
            result.setMsg("交互错误");
            return result;
        }
    }

    /**
     * oauth2认证获取code
     * @param request
     * @param resp
     * @return
     * @throws URISyntaxException
     * @throws OAuthSystemException
     */
    @RequestMapping("authorize")
    public Object authorize(HttpServletRequest request,HttpServletResponse resp) throws URISyntaxException, OAuthSystemException {
        OAuthResponse response = oauth2Service.authorize(request, resp, apiConfig);
        if(response == null) {
            return null;
        }
        HttpHeaders headers = new HttpHeaders();
        headers.setLocation(new URI(response.getLocationUri()));
        return new ResponseEntity<String>(headers, HttpStatus.valueOf(response.getResponseStatus()));
    }

    /**
     * 通过code获取accessToken
     * @param request
     * @return
     * @throws URISyntaxException
     * @throws OAuthSystemException
     */
    @RequestMapping("accessToken")
    public HttpEntity<?> accessToken(HttpServletRequest request) throws URISyntaxException, OAuthSystemException {
        OAuthResponse response = oauth2Service.accessToken(request, apiConfig);
        return new ResponseEntity<String>(  
                response.getBody(), HttpStatus.valueOf(response.getResponseStatus())); 
    }
    
    /**
     * 捕捉异常。<br>
     * 接口调用抛出的异常都会在
     * <code>AbstractInvokeTemplate.processError()</code>中执行。<br>
     * 其它情况的异常会走这里。底层都是走processError()方法。
     * @param req
     * @param response
     * @param e
     */
    @ExceptionHandler(value = Throwable.class)
    public void jsonErrorHandler(HttpServletRequest request, HttpServletResponse response, Throwable e) {
        try {
            this.invokeTemplate.processError(request, response, e);
        } catch (Throwable e2) {
            logger.error("jsonErrorHandler error", e2);
            try {
                ApiResult result = new ApiResult();
                result.setCode(Errors.SYS_ERROR.getCode());
                result.setMsg(e2.getMessage());
                response.getWriter().write(JSON.toJSONString(result));
            } catch (IOException e1) {
                logger.error(e1.getMessage(), e1);
            }
        }
    }
    
    protected Result caugthException(Throwable e) {
        String code = Errors.SYS_ERROR.getCode();
        String msg = e.getMessage();
        Object data = null;
        
        if(e instanceof ApiException) {
            ApiException apiEx = (ApiException)e;
            code = apiEx.getCode();
            msg = apiEx.getMessage();
            data = apiEx.getData();
        }
        
        return this.apiConfig.getResultCreator().createErrorResult(code, msg, data);
    }
    
    
    public void setInvokeTemplate(InvokeTemplate invokeTemplate) {
        this.invokeTemplate = invokeTemplate;
    }

    public void setWebfluxInvokeTemplate(WebfluxInvokeTemplate webfluxInvokeTemplate) {
        this.webfluxInvokeTemplate = webfluxInvokeTemplate;
    }

    /**
     * 初始化apiConfig对象。spring容器加载完毕后触发此方法，因此方法中可以使用被@Autowired注解的对象。
     * @param apiConfig
     */
    protected abstract void initApiConfig(ApiConfig apiConfig);
    
    private abstract class AbstractInvokeTemplate {
        protected abstract void afterInvoke(HttpServletRequest request, HttpServletResponse response, Object result);
        
        public Object processInvoke(HttpServletRequest request, HttpServletResponse response) {
            try {
                Object result = invoke(request, response);
                this.afterInvoke(request, response, result);
                return result;
            } catch (Throwable e) {
                return this.processError(request, response, e);
            } finally {
                ApiContext.clean();
            }
        }
        
        public Object processInvokeBySSL(HttpServletRequest request, HttpServletResponse response) {
            try {
                Object result = invokeBySSL(request, response);
                this.afterInvoke(request, response, result);
                return result;
            } catch (Throwable e) {
                return this.processError(request, response, e);
            } finally {
                ApiContext.clean();
            }
        }
        
        // 最终错误会在这里处理
        public Object processError(HttpServletRequest request, HttpServletResponse response, Throwable e) {
            Result result = caugthException(e);
            this.afterInvoke(request, response, result);
            return result;
        }
    }
    
    protected class InvokeTemplate extends AbstractInvokeTemplate {
        @Override
        protected void afterInvoke(HttpServletRequest request, HttpServletResponse response, Object result) {
            responseResult(response, result);
        }
    }
    
    protected class WebfluxInvokeTemplate extends AbstractInvokeTemplate {
        @Override
        protected void afterInvoke(HttpServletRequest request, HttpServletResponse response, Object result) {
        }
    }
    
    /* ***********************************限流内容start*********************************** */
    private static String SESSION_KEY_LIMIT_PASSWORD = "session_key_limit_password";
    
    @Override
    public void onRegistFinished(ApiConfig apiConfig) {
        LimitConfigManager limitConfigManager = apiConfig.getLimitConfigManager();
        if(limitConfigManager != null) {
            limitConfigManager.loadToLocalCache();
        }
    }

    /**
     * 进入监控页面
     * @param monitorSearch 查询参数
     * @return
     * @throws IOException 
     * @throws ServletException 
     */
    @RequestMapping("limit")
    public void limit(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        if (this.apiConfig.getLimitManager() == null) {
            response.getWriter().write("限流功能未开启");
            return;
        }
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=UTF-8");
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        
        Object value = request.getSession().getAttribute(SESSION_KEY_LIMIT_PASSWORD);
        VelocityContext context = this.buildVelocityContext(request);
        // 如果没有登陆
        if(value == null) {
            // 校验登陆密码
            if(this.checkLimitPassword(request)) {
                request.getSession().setAttribute(SESSION_KEY_LIMIT_PASSWORD, true);
                response.sendRedirect(String.valueOf(context.get("loginUrl")));
                return;
            } else { // 密码错误跳转
                request.getSession().setAttribute(SESSION_KEY_LIMIT_PASSWORD, null);
                
                ClassPathResource res = new ClassPathResource(this.apiConfig.getLoginClassPath());
                context.put("title", "限流管理");
                context.put("remark", "限流管理页面密码：");
                
                VelocityUtil.generate(context, res.getInputStream(), response.getWriter());
                return;
            }
        } else { // 已登录
            ClassPathResource res = new ClassPathResource(this.apiConfig.getLimitClassPath());

            context.put("title", "限流管理");
            
            this.processLimitVelocityContext(context);
            
            VelocityUtil.generate(context, res.getInputStream(), response.getWriter());
        }
    }
    
    /**
     * 对限流模板做额外处理
     * @param context
     */
    protected void processLimitVelocityContext(VelocityContext context) {
        
    }
    
    @RequestMapping("limit/data")
    @ResponseBody
    public Object limitData(LimitSearch apiSearch,HttpServletRequest request) throws IOException {
        if(request.getSession().getAttribute(SESSION_KEY_LIMIT_PASSWORD) == null) { // 无权限
            return -1;
        }
        LimitConfigManager limitConfigManager = this.apiConfig.getLimitConfigManager();
        long total = limitConfigManager.getTotal(apiSearch);
        List<?> list = limitConfigManager.listLimitConfig(apiSearch);
        
        Map<String, Object> map = new HashMap<>();
        map.put("total", total);
        map.put("rows", list);
        
        return map;
    }
    
    @RequestMapping("limit/modify")
    @ResponseBody
    public Object limitModify(LimitConfig limitConfig, HttpServletRequest request) throws IOException {
        if(request.getSession().getAttribute(SESSION_KEY_LIMIT_PASSWORD) == null) { // 无权限
            return -1;
        }
        if(org.apache.commons.lang.StringUtils.isBlank(limitConfig.getVersion())) {
            limitConfig.setVersion("");
        }
        Set<ConstraintViolation<LimitConfig>> validate = ApiValidator.getValidator().validate(limitConfig);
        for (ConstraintViolation<LimitConfig> c : validate) {
            String errorMsg = c.getMessage();
            throw new ApiException(errorMsg, "500");
        }
        
        String code = limitConfig.getLimitCode();
        if(NumberUtils.isNumber(code)) {
            int codeDouble = NumberUtils.toInt(code);
            if(codeDouble <= 100) {
                throw new ApiException("code值必须大于100（1~100为系统保留code）", "500");
            }
        }
        
        LimitConfigManager limitConfigManager = this.apiConfig.getLimitConfigManager();
        limitConfigManager.save(limitConfig);
        return Collections.emptyMap();
    }
    
    @RequestMapping("limit/status")
    @ResponseBody
    public Object limitStatus(@RequestBody StatusParam statusParam, HttpServletRequest request) throws IOException {
        if(request.getSession().getAttribute(SESSION_KEY_LIMIT_PASSWORD) == null) { // 无权限
            return -1;
        }
        List<String> list = statusParam.getNameVersionList();
        if(CollectionUtils.isEmpty(list)) {
            return Collections.emptyMap();
        }

        if(statusParam.getStatus() == null) {
            throw new ApiException("status不能为null", "500");
        }
        
        LimitConfigManager limitConfigManager = this.apiConfig.getLimitConfigManager();
        byte status = statusParam.getStatus().byteValue();
        for (String nameVersion : list) {
            LimitConfig limitConfig = limitConfigManager.getApiRateConfig(nameVersion);
            if(limitConfig.getStatus().byteValue() != status) {
                limitConfig.setStatus(status);
                limitConfigManager.save(limitConfig);
            }
        }
        
        return Collections.emptyMap();
    }
    
    public static class StatusParam {
        private List<String> nameVersionList;
        private Byte status;

        public List<String> getNameVersionList() {
            return nameVersionList;
        }

        public void setNameVersionList(List<String> nameVersionList) {
            this.nameVersionList = nameVersionList;
        }

        public Byte getStatus() {
            return status;
        }

        public void setStatus(Byte status) {
            this.status = status;
        }
    }
    
    protected boolean checkLimitPassword(HttpServletRequest request) {
        return this.checkPassword(request, this.apiConfig.getLimitPassword());
    }
    /* ***********************************限流内容end*********************************** */

}
